package com.my.chapter21;

import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

public class practice29 {
    public static void main(String[] args) throws InterruptedException {
        ToastQueue
                dryQueue = new ToastQueue(),
                butteredQueue = new ToastQueue(),
                toBeButteredQueue = new ToastQueue(),
                jammedQueue = new ToastQueue(),
                toBeJammedQueue = new ToastQueue(),
                finishedQueue = new ToastQueue();
        ExecutorService exec = Executors.newCachedThreadPool();
        exec.execute(new Toaster(dryQueue));
        exec.execute(new Alternator(dryQueue, toBeButteredQueue,
                toBeJammedQueue));
        exec.execute(
                new Butterer(toBeButteredQueue, butteredQueue));
        exec.execute(
                new Jammer(toBeJammedQueue, jammedQueue));
        exec.execute(new Merger(butteredQueue , jammedQueue,
                toBeButteredQueue, toBeJammedQueue, finishedQueue));
        exec.execute(new Eater(finishedQueue));
        TimeUnit.SECONDS.sleep(5);
        exec.shutdownNow();
    }
}

//问题：使用两个单独的组装线来创建涂有黄油和果酱的吐司三明治（一个用于黄油，一个用于果酱，然后把两条线合并）

class Toast {
    public enum Status {
        DRY,       //制作吐司
        BUTTERED,  //抹黄油
        JAMMED,    //涂果酱
        READY {
            public String toString() {
                return
                        BUTTERED.toString() + " & " + JAMMED.toString();
            }
        }
    }
    private Status status = Status.DRY;
    private final int id;
    public Toast(int idn) { id = idn; }
    public void butter() {
        status =
                (status == Status.DRY) ? Status.BUTTERED :
                        Status.READY;
    }
    public void jam() {
        status =
                (status == Status.DRY) ? Status.JAMMED :
                        Status.READY;
    }
    public Status getStatus() { return status; }
    public int getId() { return id; }
    public String toString() {
        return "Toast " + id + ": " + status;
    }
}

class ToastQueue extends LinkedBlockingQueue<Toast> {}

//制作吐司的任务类
class Toaster implements Runnable {
    private ToastQueue toastQueue;
    private int count;
    private Random rand = new Random(47);
    public Toaster(ToastQueue tq) { toastQueue = tq; }
    public void run() {
        try {
            while(!Thread.interrupted()) {
                TimeUnit.MILLISECONDS.sleep(
                        100 + rand.nextInt(500));
                // Make toast
                Toast t = new Toast(count++);
                System.out.println(t);
                // Insert into queue
                toastQueue.put(t);
            }
        } catch(InterruptedException e) {
            System.out.println("Toaster interrupted");
        }
        System.out.println("Toaster off");
    }
}

//涂黄油任务类
class Butterer implements Runnable {
    private ToastQueue inQueue, butteredQueue;
    public Butterer(ToastQueue in, ToastQueue buttered) {
        inQueue = in;
        butteredQueue = buttered;
    }
    public void run() {
        try {
            while(!Thread.interrupted()) {
                // Blocks until next piece of toast is available:
                Toast t = inQueue.take();
                t.butter();
                System.out.println(t);
                butteredQueue.put(t);
            }
        } catch(InterruptedException e) {
            System.out.println("Butterer interrupted");
        }
        System.out.println("Butterer off");
    }
}

//涂果酱任务类
class Jammer implements Runnable {
    private ToastQueue inQueue, jammedQueue;
    public Jammer(ToastQueue in, ToastQueue jammed) {
        inQueue = in;
        jammedQueue = jammed;
    }
    public void run() {
        try {
            while(!Thread.interrupted()) {
                // Blocks until next piece of toast is available:
                Toast t = inQueue.take();
                t.jam();
                System.out.println(t);
                jammedQueue.put(t);
            }
        } catch(InterruptedException e) {
            System.out.println("Jammer interrupted");
        }
        System.out.println("Jammer off");
    }
}

//消费者
class Eater implements Runnable {
    private ToastQueue finishedQueue;
    public Eater(ToastQueue finished) {
        finishedQueue = finished;
    }
    public void run() {
        try {
            while(!Thread.interrupted()) {
                // Blocks until next piece of toast is available:
                Toast t = finishedQueue.take();
                // Verify that all pieces are ready for consumption:
                if(t.getStatus() != Toast.Status.READY) {
                    System.out.println(">>>> Error: " + t);
                    System.exit(1);
                } else
                    System.out.println("Chomp! " + t);
            }
        } catch(InterruptedException e) {
            System.out.println("Eater interrupted");
        }
        System.out.println("Eater off");
    }
}

//分流，将吐司分别给涂黄油队列或涂果酱队列
class Alternator implements Runnable {
    private ToastQueue inQueue, out1Queue, out2Queue;
    private boolean outTo2; // control alternation
    public Alternator(ToastQueue in, ToastQueue out1,
                      ToastQueue out2) {
        inQueue = in;
        out1Queue = out1;
        out2Queue = out2;
    }
    public void run() {
        try {
            while(!Thread.interrupted()) {
                // Blocks until next piece of toast is available:
                Toast t = inQueue.take();
                if(!outTo2)
                    out1Queue.put(t);
                else
                    out2Queue.put(t);
                outTo2 = !outTo2; // change state for next time
            }
        } catch(InterruptedException e) {
            System.out.println("Alternator interrupted");
        }
        System.out.println("Alternator off");
    }
}

//合并两条线
class Merger implements Runnable {
    private ToastQueue in1Queue, in2Queue, toBeButteredQueue,
            toBeJammedQueue, finishedQueue;
    public Merger(ToastQueue in1, ToastQueue in2,
                  ToastQueue toBeButtered, ToastQueue toBeJammed,
                  ToastQueue finished) {
        in1Queue = in1;
        in2Queue = in2;
        toBeButteredQueue = toBeButtered;
        toBeJammedQueue = toBeJammed;
        finishedQueue = finished;
    }
    public void run() {
        try {
            while(!Thread.interrupted()) {
                // 阻塞直到下一块烤面包可用：
                Toast t = null;
                while(t == null) {
                    //取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,
                    //取不到时返回null
                    t = in1Queue.poll(50, TimeUnit.MILLISECONDS);
                    if(t != null)
                        break;
                    t = in2Queue.poll(50, TimeUnit.MILLISECONDS);
                }
                // 将吐司传递到适当的队列
                switch(t.getStatus()) {
                    case BUTTERED:
                        //重新将涂黄油的吐司装进该队列
                        //使其可以再次调用butter()，使其状态变为READY
                        toBeJammedQueue.put(t);
                        break;
                    case JAMMED:
                        toBeButteredQueue.put(t);
                        break;
                    default:
                        finishedQueue.put(t);
                }
            }
        } catch(InterruptedException e) {
            System.out.println("Merger interrupted");
        }
        System.out.println("Merger off");
    }
}

/*Output：
Toast 0: DRY
Toast 0: BUTTERED
Toast 0: BUTTERED & JAMMED
Chomp! Toast 0: BUTTERED & JAMMED
Toast 1: DRY
Toast 1: JAMMED
Toast 1: BUTTERED & JAMMED
Chomp! Toast 1: BUTTERED & JAMMED
Toast 2: DRY
Toast 2: BUTTERED
Toast 2: BUTTERED & JAMMED
Chomp! Toast 2: BUTTERED & JAMMED
Toast 3: DRY
Toast 3: JAMMED
Toast 3: BUTTERED & JAMMED
Chomp! Toast 3: BUTTERED & JAMMED
Toast 4: DRY
Toast 4: BUTTERED
Toast 4: BUTTERED & JAMMED
Chomp! Toast 4: BUTTERED & JAMMED
Toast 5: DRY
Toast 5: JAMMED
Toast 5: BUTTERED & JAMMED
Chomp! Toast 5: BUTTERED & JAMMED
Toast 6: DRY
Toast 6: BUTTERED
Toast 6: BUTTERED & JAMMED
Chomp! Toast 6: BUTTERED & JAMMED
Toast 7: DRY
Toast 7: JAMMED
Toast 7: BUTTERED & JAMMED
Chomp! Toast 7: BUTTERED & JAMMED
Toast 8: DRY
Toast 8: BUTTERED
Toast 8: BUTTERED & JAMMED
Chomp! Toast 8: BUTTERED & JAMMED
Toast 9: DRY
Toast 9: JAMMED
Toast 9: BUTTERED & JAMMED
Chomp! Toast 9: BUTTERED & JAMMED
Toast 10: DRY
Toast 10: BUTTERED
Toast 10: BUTTERED & JAMMED
Chomp! Toast 10: BUTTERED & JAMMED
Eater interrupted
Alternator interrupted
Merger interrupted
Jammer interrupted
Toaster interrupted
Butterer interrupted
Toaster off
Jammer off
Merger off
Alternator off
Eater off
Butterer off
*/


